<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。JCAT 由中国团队开发维护。
//  正在使用的这个版本是：0.4.0 / SVN信息: $Id: class.JCAT_UIGtkGlade.php 1490 2009-03-19 12:38:51Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [下载(HTTP)] http://code.google.com/p/jcat-php/downloads/list
//    [下载(svn)] svn checkout http://jcat-php.googlecode.com/svn/branches/0.4.0/Framework/ JCAT0.4
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.com/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.com/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/




/**
 * 为 Gtk Glade 提供模版引擎 
 *
 * @author		alee
 * @access		public
 */
class JCAT_UIGtkGlade extends JCAT_UI
{

	/**
	 * 设置一个 分析器目录
	 * 
	 * @access	public
	 * @param	$sDir	string	分析器目录
	 * @static
	 * @return	void
	 */
	static public function AddParserDir( $sDir ) 
	{
		JCAT_ASSERT::ASSERT_STRING($sDir) ;
		JCAT_ASSERT::ASSERT_DIR($sDir) ;
		
		$sDirPath = JCAT_Global::TidyPath($sDir) ;
		
		if( !in_array($sDirPath,self::$arrParserDirs) )
			self::$arrParserDirs[] = $sDirPath ;
	}



	/**
	 * 清空已设置的分析器目录，并返回原有的数量
	 * 
	 * @access	public
	 * @static
	 * @return	int
	 */
	static public function ClearParserDir(  ) 
	{
		$nCount = count(self::$arrParserDirs) ;
		self::$arrParserDirs = array() ;
		return $nCount ;
	}



	/**
	 * 创建一个默认的 分析器管理器
	 * 
	 * @access	public
	 * @static
	 * @return	JCAT_UIObjectProcessorManager
	 */
	static public function GetDefaultParserManager(  ) 
	{
		$aParserManager = new JCAT_UIObjectProcessorManager() ;
		
		// 加入 Code 和 Node 分析器
		JCAT_UIGtkGladeWidgetParser::RegistorToProcessorManager($aParserManager) ;

		// 自动加入其他编译器
		foreach(self::$arrParserDirs as $sDirPath)
		{
			$aParserManager->AddAutoloadProcessorDir($sDirPath) ;
		}

		return $aParserManager ;
	}



	/**
	 * 创建一个全局的 默认模板目录管理器
	 * 
	 * @access	public
	 * @static
	 * @return	void
	 */
	static public function CreateDefaultTemplateDirManger(  )
	{
		self::$aUITemplateFileManager = new JCAT_UITemplateFileManager() ;
	}

	/**
	 * 设置一个模版文件存放目录
	 * 
	 * @access	public
	 * @param	$sDir	string	模版文件存放目录
	 * @static
	 * @return	void
	 */
	static public function AddTemplateDir($sDir) 
	{
		return self::$aUITemplateFileManager->AddTemplateDir($sDir) ;
	}



	/**
	 * 清空已经设置的模版文件目录
	 * 
	 * @access	public
	 * @static
	 * @return	int
	 */
	static public function ClearTemplateDirs() 
	{
		return self::$aUITemplateFileManager->ClearTemplateDirs() ;
	}



	/**
	 * 创建一个 模版目录  的备忘录
	 * 
	 * @access	public
	 * @static
	 * @return	array
	 */
	static public function CreateTemplateDirsMemento() 
	{ return self::$aUITemplateFileManager->CreateTemplateDirsMemento() ; }



	/**
	 * 使用 一个备忘录
	 * 
	 * @access	public
	 * @param	$arrMemento	array	备忘录
	 * @static
	 * @return	old_var
	 */
	static public function SetTemplateDirsMemento( array $arrMemento )
	{ return self::$aUITemplateFileManager->SetTemplateDirsMemento($arrMemento) ; }


	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @static
	 * @return	JCAT_ArrayReverseIterator
	 */
	static public function CreateTemplateDirIterator()
	{ return self::$aUITemplateFileManager->CreateTemplateDirIterator() ; }

	/**
	 * 根据模版 文件名查找 文件
	 * 
	 * @access	public
	 * @param	$sTemplateFile					string	模版文件名称
	 * @static
	 * @return	string
	 */
	static public function FindTemplate( $sTemplateFile )
	{ return self::$aUITemplateFileManager->FindTemplate($sTemplateFile) ; }

	/**
	 * 取得 真实的 WidgetID
	 * 
	 * @access	public
	 * @param	$WidgetId	string	Widget ID
	 * @return	string
	 */
	static public function TrimWidgetID( $WidgetId )
	{
		return preg_replace('/@(View|UICtrl):([^:]+)/','\\2__\\1',$WidgetId) ;
	}
	
	/**
	 * 为一个Glade文件生成一个不重复的 Class名称
	 *
	 * @access	public
	 * @param	$sGladeFile	string	Glade文件路径
	 * @return	void
	 */
	static public function CreateGladeClassName( $sGladeFile )
	{
		if( !is_file($sGladeFile) )
			$sGladePath = self::FindTemplate($sGladeFile) ;
		else
			$sGladePath =& $sGladeFile ;

		JCAT_ASSERT::ASSERT_FILE($sGladePath) ;
		return 'JCAT_GtkGlade_'.md5_file($sGladePath) ;
	}
	
	/**
	 * 窗体变量名称
	 * 
	 * @access	public
	 * @param	$WidgetOrId	JCAT_UIGtkGladeWidget,string	Widget对象 或 Widget ID
	 * @return	string
	 */
	static public function GetWidgetVariableName( $WidgetOrId )
	{
		if( is_object($WidgetOrId) )
		{
			JCAT_ASSERT::ASSERT_INSTANCE($WidgetOrId,'JCAT_UIGtkGladeWidget') ;
			$sVariable = $WidgetOrId->GetWidgetId() ;
		}
		else if( is_string($WidgetOrId) )
		{
			$sVariable = $WidgetOrId ;
		}
		
		else
		{
			JCAT_ASSERT::ASSERT_(0,JCAT_Language::SentenceEx('参数 $WidgetOrId 只能为 JCAT_UIGtkGladeWidget对象  或  string','JCAT',null)) ;
		}

		$sVariable= self::TrimWidgetID($sVariable) ;
		
		return str_replace('-','_',$sVariable) ;
	}
	
	
	
	/**
	 * 窗体创建函数名称
	 * 
	 * @access	public
	 * @param	$WidgetOrId		Widget对象 或 Widget ID
	 * @return	string
	 */
	static public function GetWidgetCreateFunctionName( $WidgetOrId )
	{
		JCAT_ASSERT::ASSERT_ISTHESE($WidgetOrId,array('JCAT_UIGtkGladeWidget','string')) ;
		
		$sVariableName = self::GetWidgetVariableName($WidgetOrId) ;
		return "Create_{$sVariableName}" ;
		//return "Create_{$sWidgetClass}_{$sVariableName}" ;
	}
	
	/**
	 * 创建窗体
	 *
	 * @access	public
	 * @param	$sGladePath						string		Glade 模版文件路径
	 * @param	$sWidgetId						string		窗体名称
	 * @param	$arrObjectForSignal=array()		array		用于响应 Signal 事件的对象, 数组键名做为 对象的变量名
	 * @return	GtkWidget, null
	 */
	public function Create( $sGladeFile, $sWidgetId, array $arrObjectForSignal=array() )
	{
		JCAT_ASSERT::ASSERT_STRING($sGladeFile) ;
		JCAT_ASSERT::ASSERT_STRING($sWidgetId) ;
		
		// Glade 文件路径
		if( is_file($sGladeFile) )
		{
			$sGladePath =& $sGladeFile ;
		}
		else
		{
			$sGladePath = self::FindTemplate($sGladeFile) ;
		}
		JCAT_ASSERT::ASSERT_FILE($sGladePath) ;
			
		// 载入 窗体创建 类
		$sCreateClassName = $this->LoadGtkWidgetCreatorClass($sGladePath) ;
		JCAT_ASSERT::ASSERT_ISCLASS($sCreateClassName,'JCAT_UIGtkWidgetCreator') ;
		
		// 创建 窗体创建 对象
		$aCreator = new $sCreateClassName($this) ;
		$Callback = array($aCreator,'GetWidget');
		JCAT_ASSERT::ASSERT_(is_callable($Callback,false),JCAT_Language::SentenceEx('Glade模版文件“%s”的 编译文件失效。','JCAT',null, $sGladePath)) ;

		// 创建 窗体
		$aWidget = call_user_func_array( $Callback, array($sWidgetId,$arrObjectForSignal) ) ;
		JCAT_ASSERT::ASSERT_ISTHESE($aWidget,array('GtkWidget','null')) ;

		// 返回 窗体
		return $aWidget ;
	}


	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$sGladePath		string			what's this
	 * @return	string, null
	 */
	public function LoadGtkWidgetCreatorClass($sGladePath)
	{
		if( !is_file($sGladePath) )
		{
			return null ;
		}
		
		// 编译文件路径
		$sCompiledPath = $this->GetCompiledPath($sGladePath) ;
		
		// 检查编译文件有效
		if( $this->IsCompiledFileExpired($sGladePath,$sCompiledPath) )
		{
			$sCompiledPath = $this->Compile($sGladePath) ;
		}
		
		// 编译失败
		if( !is_file($sCompiledPath) )
		{
			return null ;
		}
		
		// 载入 Compiled 文件
		$sCreateClassName = self::CreateGladeClassName($sGladePath) ;
		if( !class_exists($sCreateClassName) )
		{
			include $sCompiledPath ;
		}
		
		// 返回
		return $sCreateClassName ;
	}

	/**
	 * 创建窗体
	 *
	 * @access	public
	 * @param	$sGladePath			string			Glade 模版文件路径
	 * @param	$sWidgetId			string			窗体名称
	 * @param	$aView=null			JCAT_ViewGtk	所属视图
	 * @param	$bCreateNew=false	bool			创建新窗体
	 * @return	GtkWidget, null
	 */
	public function GetWidget( $sGladeFile, $sWidgetId, JCAT_ViewGtk $aView=null, $bCreateNew=false )
	{
	}
	
	
	/**
	 * 生成编译文件
	 * 
	 * @access	protected
	 * @param	$sTemplatePath		string		模版路径
	 * @param	$sCompiledPath		string		编译文件路径
	 * @param	& $sCompiled		string		各个 UIObject编译内容
	 * @return	void
	 */
	protected function MakeCompiledFile($sTemplatePath,$sCompiledPath,& $sCompiled)
	{
		// 创建 编译文件目录
		$sCompiledDir = dirname($sCompiledPath) ;
		if( !is_dir($sCompiledDir) )
		{
			if( !mkdir($sCompiledDir,0777,true) )
			{
				throw new JCAT_Exception( JCAT_Language::SentenceEx('无法为模版文件创建编译目录：“%s”','JCAT',null,$sCompiledDir), __macro_exception_code__ ) ;
			}
		}
		
		$sGladeClassName = self::CreateGladeClassName($sTemplatePath) ;
		$sWidgetTree = serialize($this->arrWidgetsTree) ;
		$sWidgetIds = serialize( $this->arrWidgetIds ) ;
		$nNow = date('Y.m.d G:i:s') ;


		$sCompiled = "<?


/**
 * Gtk窗体 创建器
 * 此文件根据 Glade窗口模版文件 自动产生，当 原Glade文件更改后，此文件也会及时重建。
 *
 * !注意：此文件由 JCAT 框架自动产生、维护，任何情况下都不应该手工编辑此文件，以免 JCAT 框架维护此文件时丢弃手工更改的内容。
 *
 * @author	JCAT_UIGtkGlade
 * @create	{$nNow}
 * @access	public
 */
class {$sGladeClassName} extends JCAT_UIGtkWidgetCreator
{
	// 公共方法 ///////////////////////////////////////////////////////////
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	\$aUI	JCAT_UIGtkGlade
	 * @return	array
	 */
	public function {$sGladeClassName}(JCAT_UIGtkGlade \$aUI)
	{
		\$this->JCAT_UIGtkWidgetCreator(\$aUI) ;
	
		\$this->arrWidgetTree = unserialize('{$sWidgetTree}') ;
		\$this->arrWidgetIds = unserialize('{$sWidgetIds}') ;
		\$this->sTemplatePath = '{$sTemplatePath}' ;
	}


	// 私有方法 ///////////////////////////////////////////////
{$sCompiled}

}

?>" ;
		
		file_put_contents($sCompiledPath,$sCompiled) ;
	}



	protected function CompileUIObject()
	{
		$this->arrTotalWidgets = array() ;
		$this->arrWidgetsTree = array() ;
		$this->arrWidgetIds = array() ;
		
		return $sCompiled = JCAT_UI::CompileUIObject() ;
	}
	
	
	/**
	 * 
	 *
	 * @access	public
	 * @param	$sClass			What's this Parameter ?
	 * @param	$sWidgetId		What's this Parameter ?
	 * @param	$sParentId		What's this Parameter ?
	 * @return	void
	 */
	public function _AddWidget($sWidgetName,$sParentName=null)
	{
		if( $sParentName===null )
		{
			// 已经存在的节点
			if( isset($this->arrTotalWidgets[$sWidgetName]) )
			{
				// Nothing ...
			}
			
			// 创建一个顶级节点
			else
			{
				$this->arrWidgetsTree[ $sWidgetName ] = array() ;
				$this->arrTotalWidgets[$sWidgetName] =& $this->arrWidgetsTree[ $sWidgetName ] ;
			}
		}
		
		else
		{
				
			JCAT_ASSERT::ASSERT_ISTHESE($this->arrTotalWidgets[$sParentName],array('array')) ;
			$this->arrTotalWidgets[$sParentName][$sWidgetName] = array() ;
			$this->arrTotalWidgets[$sWidgetName] =& $this->arrTotalWidgets[$sParentName][$sWidgetName] ;
		}
	}
	
	
	/**
	 * 检查同名ID的 窗体
	 *
	 * @access	public
	 * @param	$sWidgetId		窗体ID
	 * @param	$sWidgetClass	窗体Class
	 * @return	void
	 */
	public function _CheckSameIDWidget($sWidgetId,$sWidgetClass)
	{
		JCAT_ASSERT::ASSERT_STRING($sWidgetId) ;
		JCAT_ASSERT::ASSERT_STRING($sWidgetClass) ;
		
		if( isset($this->arrWidgetIds[$sWidgetId]) )
		{
			throw new JCAT_Exception( JCAT_Language::SentenceEx('在同一个 Glade 文件中，不应该出现ID（Name）相同的窗体。相同ID的两个窗体的类型分别为：“%s”、“%s”','JCAT',null,$this->arrWidgetIds[$sWidgetId],$sWidgetClass), __macro_exception_code__ ) ;
		}

		$this->arrWidgetIds[$sWidgetId] = $sWidgetClass ;
	}
	
	
	
	/**
	 * what's this
	 * 
	 * @access	public
	 * @param	$aWidget	GtkWidget			what's this
	 * @return	array
	 * @static
	 */
	static public function GetWidgetCreator(GtkWidget $aWidget)
	{
		return $aWidget->get_data('creator') ;
	}

	// 属性 ///////////////////////////////////////////////////////////////////////////////

	/**
	 * 缺省的全局模板目录管理器
	 * 
	 * @access	private
	 * @static
	 * @var		JCAT_UITemplateFileManager
	 */
	static private $aUITemplateFileManager ;


	/**
	 * 分析器目录
	 * 
	 * @access	private
	 * @var		array:string
	 */
	static private $arrParserDirs = array() ;



	private $arrWidgetVariables = array() ;
	
	
	private $arrTotalWidgets = array() ;
	private $arrWidgetsTree = array() ;
	
	private $arrWidgetIds = array() ;
	
}



// 常量定义
// --------------------------------------------------------------------

if( JCAT_Package::ClassExists('GObject') )
{
		if( defined("GObject::TYPE_STRING") )
	{
		define('JCAT_Gtk_TYPE_STRING',GObject::TYPE_STRING) ;
		define('JCAT_Gtk_TYPE_LONG',GObject::TYPE_LONG) ;
		define('JCAT_Gtk_TYPE_DOUBLE',GObject::TYPE_DOUBLE) ;
		define('JCAT_Gtk_TYPE_INVALID',GObject::TYPE_INVALID) ;
		define('JCAT_Gtk_TYPE_NONE',GObject::TYPE_NONE) ;
		define('JCAT_Gtk_TYPE_INTERFACE',GObject::TYPE_INTERFACE) ;
		define('JCAT_Gtk_TYPE_CHAR',GObject::TYPE_CHAR) ;
		define('JCAT_Gtk_TYPE_BOOLEAN',GObject::TYPE_BOOLEAN) ;
		define('JCAT_Gtk_TYPE_ENUM',GObject::TYPE_ENUM) ;
		define('JCAT_Gtk_TYPE_FLAGS',GObject::TYPE_FLAGS) ;
		define('JCAT_Gtk_TYPE_POINTER',GObject::TYPE_POINTER) ;
		define('JCAT_Gtk_TYPE_BOXED',GObject::TYPE_BOXED) ;
		define('JCAT_Gtk_TYPE_PARAM',GObject::TYPE_PARAM) ;
		define('JCAT_Gtk_TYPE_OBJECT',GObject::TYPE_OBJECT) ;
		define('JCAT_Gtk_TYPE_PHP_VALUE',GObject::TYPE_PHP_VALUE) ;
	}
	
	else 
	{
		define('JCAT_Gtk_TYPE_STRING',Gtk::TYPE_STRING) ;
		define('JCAT_Gtk_TYPE_LONG',Gtk::TYPE_LONG) ;
		define('JCAT_Gtk_TYPE_DOUBLE',Gtk::TYPE_DOUBLE) ;
		define('JCAT_Gtk_TYPE_INVALID',Gtk::TYPE_INVALID) ;
		define('JCAT_Gtk_TYPE_NONE',Gtk::TYPE_NONE) ;
		define('JCAT_Gtk_TYPE_INTERFACE',Gtk::TYPE_INTERFACE) ;
		define('JCAT_Gtk_TYPE_CHAR',Gtk::TYPE_CHAR) ;
		define('JCAT_Gtk_TYPE_BOOLEAN',Gtk::TYPE_BOOLEAN) ;
		define('JCAT_Gtk_TYPE_ENUM',Gtk::TYPE_ENUM) ;
		define('JCAT_Gtk_TYPE_FLAGS',Gtk::TYPE_FLAGS) ;
		define('JCAT_Gtk_TYPE_POINTER',Gtk::TYPE_POINTER) ;
		define('JCAT_Gtk_TYPE_BOXED',Gtk::TYPE_BOXED) ;
		define('JCAT_Gtk_TYPE_PARAM',Gtk::TYPE_PARAM) ;
		define('JCAT_Gtk_TYPE_OBJECT',Gtk::TYPE_OBJECT) ;
		define('JCAT_Gtk_TYPE_PHP_VALUE',Gtk::TYPE_PHP_VALUE) ;
	}
}


// 创建缺省的 模板目录管理器
// --------------------------------------------------------------------
JCAT_UIGtkGlade::CreateDefaultTemplateDirManger() ;


?>